package com.common.frame.utils

import android.app.Activity
import android.content.Context
import android.content.res.Resources
import android.graphics.*
import android.graphics.drawable.Drawable
import android.media.ExifInterface
import android.net.Uri
import android.provider.MediaStore
import android.text.TextUtils
import android.view.View
import java.io.*
import java.net.URI
import kotlin.math.abs

object BitmapUtil {
    /**
     * 图片压缩处理（使用Options的方法）
     *
     *
     * <br></br>
     * **说明** 使用方法：
     * 首先你要将Options的inJustDecodeBounds属性设置为true，BitmapFactory.decode一次图片 。
     * 然后将Options连同期望的宽度和高度一起传递到到本方法中。
     * 之后再使用本方法的返回值做参数调用BitmapFactory.decode创建图片。
     *
     *
     * <br></br>
     * **说明** BitmapFactory创建bitmap会尝试为已经构建的bitmap分配内存
     * ，这时就会很容易导致OOM出现。为此每一种创建方法都提供了一个可选的Options参数
     * ，将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存
     * ，返回值也不再是一个Bitmap对象， 而是null。虽然Bitmap是null了，但是Options的outWidth、
     * outHeight和outMimeType属性都会被赋值。
     *
     * @param reqWidth  目标宽度,这里的宽高只是阀值，实际显示的图片将小于等于这个值
     * @param reqHeight 目标高度,这里的宽高只是阀值，实际显示的图片将小于等于这个值
     */
    fun calculateInSampleSize(
        options: BitmapFactory.Options, reqWidth: Int,
        reqHeight: Int
    ): BitmapFactory.Options {
        // 源图片的高度和宽度
        val height = options.outHeight
        val width = options.outWidth
        var inSampleSize = 1
//        if (height > 400 || width > 450) {
        if (height > reqHeight || width > reqWidth) {
            // 计算出实际宽高和目标宽高的比率
            val heightRatio = Math.round(height.toFloat() / reqHeight.toFloat())
            val widthRatio = Math.round(width.toFloat() / reqWidth.toFloat())
            // 选择宽和高中最小的比率作为inSampleSize的值，这样可以保证最终图片的宽和高
            // 一定都会大于等于目标的宽和高。
            inSampleSize = if (heightRatio < widthRatio)
                heightRatio
            else
                widthRatio
        }
//        }

        // 设置压缩比例
        options.inSampleSize = inSampleSize
        options.inJustDecodeBounds = false
        return options
    }

    /**
     * 获取一个指定大小的bitmap
     *
     * @param res       Resources
     * @param resId     图片ID
     * @param reqWidth  目标宽度
     * @param reqHeight 目标高度
     */
    fun getBitmapFromResource(
        res: Resources, resId: Int,
        reqWidth: Int, reqHeight: Int
    ): Bitmap {
        var options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(res, resId, options)
        options = calculateInSampleSize(
            options, reqWidth,
            reqHeight
        )
        return BitmapFactory.decodeResource(res, resId, options)

        // 通过JNI的形式读取本地图片达到节省内存的目的
//        val options = BitmapFactory.Options()
//        options.inPreferredConfig = Bitmap.Config.RGB_565
//        options.inPurgeable = true
//        options.inInputShareable = true
//        val `is` = res.openRawResource(resId)
//        return getBitmapFromStream(`is`, null, reqWidth, reqHeight)
    }

    /**
     * 获取一个指定大小的bitmap
     *
     * @param reqWidth  目标宽度
     * @param reqHeight 目标高度
     */
    fun getBitmapFromFile(
        pathName: String, reqWidth: Int,
        reqHeight: Int
    ): Bitmap {
        var options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(pathName, options)
        options = calculateInSampleSize(options, reqWidth, reqHeight)
        return BitmapFactory.decodeFile(pathName, options)
    }


    /**
     * 获取一个指定大小的bitmap
     *
     * @param data      Bitmap的byte数组
     * @param offset    image从byte数组创建的起始位置
     * @param length    the number of bytes, 从offset处开始的长度
     * @param reqWidth  目标宽度
     * @param reqHeight 目标高度
     */
    fun getBitmapFromByteArray(
        data: ByteArray, offset: Int,
        length: Int, reqWidth: Int, reqHeight: Int
    ): Bitmap {
        var options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeByteArray(data, offset, length, options)
        options = calculateInSampleSize(options, reqWidth, reqHeight)
        return BitmapFactory.decodeByteArray(data, offset, length, options)
    }

    /**
     * 把bitmap转化为bytes
     *
     * @param bitmap 源Bitmap
     * @return Byte数组
     */
    fun getBytesFromBitmap(bitmap: Bitmap): ByteArray {
        val baos = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos)
        return baos.toByteArray()
    }

    /**
     * Stream转换成Byte
     *
     * @param inputStream InputStream
     * @return Byte数组
     */
    fun getBytesFromStream(inputStream: InputStream): ByteArray {
        val os = ByteArrayOutputStream(1024)
        val buffer = ByteArray(1024)
        var len = inputStream.read(buffer)
        try {
            while (len >= 0) {
                os.write(buffer, 0, len)
                len = inputStream.read(buffer)
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return os.toByteArray()
    }

    /**
     * 获取一个指定大小的bitmap
     *
     * @param b Byte数组
     * @return 需要的Bitmap
     */
    fun getBitmapFromBytes(b: ByteArray): Bitmap? {
        return if (b.isNotEmpty()) {
            BitmapFactory.decodeByteArray(b, 0, b.size)
        } else {
            null
        }
    }


    /**
     * 获取一个指定大小的bitmap
     *
     * @param is         从输入流中读取Bitmap
     * @param outPadding If not null, return the padding rect for the bitmap if it
     * exists, otherwise set padding to [-1,-1,-1,-1]. If no bitmap
     * is returned (null) then padding is unchanged.
     * @param reqWidth   目标宽度
     * @param reqHeight  目标高度
     */
    fun getBitmapFromStream(
        `is`: InputStream, outPadding: Rect?,
        reqWidth: Int, reqHeight: Int
    ): Bitmap {
        var options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeStream(`is`, outPadding, options)
        options = calculateInSampleSize(options, reqWidth, reqHeight)
        return Bitmap.createScaledBitmap(
            BitmapFactory.decodeStream(`is`, outPadding, options)!!,
            reqWidth,
            reqHeight,
            true
        )

    }

    /**
     * 从View获取Bitmap
     *
     * @param view View
     * @return Bitmap
     */
    fun getBitmapFromView(view: View): Bitmap {
        val bitmap = Bitmap.createBitmap(
            view.width, view.height,
            Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(bitmap)

        view.layout(view.left, view.top, view.right, view.bottom)
        view.draw(canvas)

        return bitmap
    }

    fun createBitmap(width: Int, height: Int): Bitmap {
        return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    }

    /**
     * 把一个View的对象转换成bitmap
     *
     * @param view View
     * @return Bitmap
     */
    fun getBitmapFromView2(view: View): Bitmap? {

        view.clearFocus()
        view.isPressed = false

        // 能画缓存就返回false
        val willNotCache = view.willNotCacheDrawing()
        view.setWillNotCacheDrawing(false)
        val color = view.drawingCacheBackgroundColor
        view.drawingCacheBackgroundColor = 0
        if (color != 0) {
            view.destroyDrawingCache()
        }
        view.buildDrawingCache()
        val cacheBitmap = view.drawingCache ?: return null
        val bitmap = Bitmap.createBitmap(cacheBitmap)
        // Restore the view
        view.destroyDrawingCache()
        view.setWillNotCacheDrawing(willNotCache)
        view.drawingCacheBackgroundColor = color
        return bitmap
    }

    /**
     * 将Drawable转化为Bitmap
     *
     * @param drawable Drawable
     * @return Bitmap
     */
    fun getBitmapFromDrawable(drawable: Drawable): Bitmap {
        val width = drawable.intrinsicWidth
        val height = drawable.intrinsicHeight
        val bitmap = Bitmap.createBitmap(
            width, height, if (drawable
                    .opacity != PixelFormat.OPAQUE
            )
                Bitmap.Config.ARGB_8888
            else
                Bitmap.Config.RGB_565
        )
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, width, height)
        drawable.draw(canvas)
        return bitmap

    }

    /**
     * 合并Bitmap
     * @param bgd 背景Bitmap
     * @param fg 前景Bitmap
     * @return 合成后的Bitmap
     */
    fun combineImages(bgd: Bitmap, fg: Bitmap): Bitmap {
        val bmp: Bitmap

        val width = if (bgd.width > fg.width)
            bgd.width
        else
            fg
                .width
        val height = if (bgd.height > fg.height)
            bgd.height
        else
            fg
                .height

        bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val paint = Paint()
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)

        val canvas = Canvas(bmp)
        canvas.drawBitmap(bgd, 0f, 0f, null)
        canvas.drawBitmap(fg, 0f, 0f, paint)

        return bmp
    }

    /**
     * 合并
     * @param bgd 后景Bitmap
     * @param fg 前景Bitmap
     * @return 合成后Bitmap
     */
    fun combineImagesToSameSize(bgd: Bitmap, fg: Bitmap): Bitmap {
        var bgd = bgd
        var fg = fg
        val bmp: Bitmap

        val width = if (bgd.width < fg.width)
            bgd.width
        else
            fg
                .width
        val height = if (bgd.height < fg.height)
            bgd.height
        else
            fg
                .height

        if (fg.width != width && fg.height != height) {
            fg = zoom(fg, width, height)
        }
        if (bgd.width != width && bgd.height != height) {
            bgd = zoom(bgd, width, height)
        }

        bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val paint = Paint()
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)

        val canvas = Canvas(bmp)
        canvas.drawBitmap(bgd, 0f, 0f, null)
        canvas.drawBitmap(fg, 0f, 0f, paint)

        return bmp
    }

    /**
     * 放大缩小图片
     *
     * @param bitmap 源Bitmap
     * @param w 宽
     * @param h 高
     * @return 目标Bitmap
     */
    fun zoom(bitmap: Bitmap, w: Int, h: Int): Bitmap {
        val width = bitmap.width
        val height = bitmap.height
        val matrix = Matrix()
        val scaleWidth = w.toFloat() / width
        val scaleHeight = h.toFloat() / height
        matrix.postScale(scaleWidth, scaleHeight)
        return Bitmap.createBitmap(
            bitmap, 0, 0, width, height,
            matrix, true
        )
    }

    /**
     * 获得圆角图片的方法
     *
     * @param bitmap 源Bitmap
     * @param roundPx 圆角大小
     * @return 期望Bitmap
     */
    fun getRoundedCornerBitmap(bitmap: Bitmap, roundPx: Float): Bitmap {

        val output = Bitmap.createBitmap(
            bitmap.width,
            bitmap.height, Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(output)

        val color = 0xff424242.toInt()
        val paint = Paint()
        val rect = Rect(0, 0, bitmap.width, bitmap.height)
        val rectF = RectF(rect)

        paint.isAntiAlias = true
        canvas.drawARGB(0, 0, 0, 0)
        paint.color = color
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint)

        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, rect, rect, paint)

        return output
    }

    /**
     * 获得带倒影的图片方法
     *
     * @param bitmap 源Bitmap
     * @return 带倒影的Bitmap
     */
    fun createReflectionBitmap(bitmap: Bitmap): Bitmap {
        val reflectionGap = 4
        val width = bitmap.width.toFloat()
        val height = bitmap.height.toFloat()

        val matrix = Matrix()
        matrix.preScale(1f, -1f)

        val reflectionImage = Bitmap.createBitmap(
            bitmap, 0, (height / 2).toInt(),
            width.toInt(), (height / 2).toInt(), matrix, false
        )

        val bitmapWithReflection = Bitmap.createBitmap(
            width.toInt(),
            (height + height / 2).toInt(), Bitmap.Config.ARGB_8888
        )

        val canvas = Canvas(bitmapWithReflection)
        canvas.drawBitmap(bitmap, 0f, 0f, null)
        val deafalutPaint = Paint()
        canvas.drawRect(0f, height, width, height + reflectionGap, deafalutPaint)

        canvas.drawBitmap(reflectionImage, 0f, height + reflectionGap, null)

        val paint = Paint()
        val shader = LinearGradient(
            0f, bitmap.height.toFloat(), 0f,
            (bitmapWithReflection.height + reflectionGap).toFloat(), 0x70ffffff,
            0x00ffffff, Shader.TileMode.CLAMP
        )
        paint.setShader(shader)
        // Set the Transfer mode to be porter duff and destination in
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
        // Draw a rectangle using the paint with our linear gradient
        canvas.drawRect(
            0f,
            height,
            width,
            (bitmapWithReflection.height + reflectionGap).toFloat(),
            paint
        )

        return bitmapWithReflection
    }

    /**
     * 压缩图片大小
     *
     * @param image 源Bitmap
     * @return 压缩后的Bitmap
     */
    fun compressImage(image: Bitmap): Bitmap {

        val baos = ByteArrayOutputStream()
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos)// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        var options = 100
        while (baos.toByteArray().size / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset()// 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos)// 这里压缩options%，把压缩后的数据存放到baos中
            options -= 10// 每次都减少10
        }
        val isBm = ByteArrayInputStream(baos.toByteArray())// 把压缩后的数据baos存放到ByteArrayInputStream中
        return BitmapFactory.decodeStream(isBm, null, null)!!
    }

    /**
     * 将彩色图转换为灰度图
     *
     * @param img 源Bitmap
     * @return 返回转换好的位图
     */
    fun convertGreyImg(img: Bitmap): Bitmap {
        val width = img.width // 获取位图的宽
        val height = img.height // 获取位图的高

        val pixels = IntArray(width * height) // 通过位图的大小创建像素点数组

        img.getPixels(pixels, 0, width, 0, 0, width, height)
        val alpha = 0xFF shl 24
        for (i in 0 until height) {
            for (j in 0 until width) {
                var grey = pixels[width * i + j]

                val red = grey and 0x00FF0000 shr 16
                val green = grey and 0x0000FF00 shr 8
                val blue = grey and 0x000000FF

                grey =
                    (red.toFloat() * 0.3 + green.toFloat() * 0.59 + blue.toFloat() * 0.11).toInt()
                grey = alpha or (grey shl 16) or (grey shl 8) or grey
                pixels[width * i + j] = grey
            }
        }
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
        result.setPixels(pixels, 0, width, 0, 0, width, height)
        return result
    }

    /**
     * 转换图片成圆形
     *
     * @param bitmap 传入Bitmap对象
     * @return 圆形Bitmap
     */
    fun getRoundBitmap(bitmap: Bitmap): Bitmap {
        var width = bitmap.width
        var height = bitmap.height
        val roundPx: Float
        val left: Float
        val top: Float
        val right: Float
        val bottom: Float
        val dst_left: Float
        val dst_top: Float
        val dst_right: Float
        val dst_bottom: Float
        if (width <= height) {
            roundPx = (width / 2).toFloat()
            top = 0f
            bottom = width.toFloat()
            left = 0f
            right = width.toFloat()
            height = width
            dst_left = 0f
            dst_top = 0f
            dst_right = width.toFloat()
            dst_bottom = width.toFloat()
        } else {
            roundPx = (height / 2).toFloat()
            val clip = ((width - height) / 2).toFloat()
            left = clip
            right = width - clip
            top = 0f
            bottom = height.toFloat()
            width = height
            dst_left = 0f
            dst_top = 0f
            dst_right = height.toFloat()
            dst_bottom = height.toFloat()
        }

        val output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(output)

        val color = 0xff424242.toInt()
        val paint = Paint()
        val src = Rect(
            left.toInt(), top.toInt(), right.toInt(),
            bottom.toInt()
        )
        val dst = Rect(
            dst_left.toInt(), dst_top.toInt(),
            dst_right.toInt(), dst_bottom.toInt()
        )
        val rectF = RectF(dst)

        paint.isAntiAlias = true

        canvas.drawARGB(0, 0, 0, 0)
        paint.color = color
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint)

        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, src, dst, paint)
        return output
    }

    /**
     * Returns a Bitmap representing the thumbnail of the specified Bitmap. The
     * size of the thumbnail is defined by the dimension
     * android.R.dimen.launcher_application_icon_size.
     *
     *
     * This method is not thread-safe and should be invoked on the UI thread
     * only.
     *
     * @param bitmap  The bitmap to get a thumbnail of.
     * @param context The application's context.
     * @return A thumbnail for the specified bitmap or the bitmap itself if the
     * thumbnail could not be created.
     */
    fun createThumbnailBitmap(bitmap: Bitmap, context: Context): Bitmap {
        var sIconWidth = -1
        var sIconHeight = -1
        val resources = context.resources
        sIconHeight = resources.getDimension(android.R.dimen.app_icon_size).toInt()
        sIconWidth = sIconHeight

        val sPaint = Paint()
        val sBounds = Rect()
        val sOldBounds = Rect()
        val sCanvas = Canvas()

        var width = sIconWidth
        var height = sIconHeight

        sCanvas.drawFilter =
            PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG)

        val bitmapWidth = bitmap.width
        val bitmapHeight = bitmap.height

        if (width > 0 && height > 0) {
            if (width < bitmapWidth || height < bitmapHeight) {
                val ratio = bitmapWidth.toFloat() / bitmapHeight

                if (bitmapWidth > bitmapHeight) {
                    height = (width / ratio).toInt()
                } else if (bitmapHeight > bitmapWidth) {
                    width = (height * ratio).toInt()
                }

                val c = if (width == sIconWidth && height == sIconHeight)
                    bitmap
                        .config
                else
                    Bitmap.Config.ARGB_8888
                val thumb = Bitmap.createBitmap(
                    sIconWidth,
                    sIconHeight, c
                )
                sCanvas.setBitmap(thumb)
                sPaint.isDither = false
                sPaint.isFilterBitmap = true
                sBounds.set(
                    (sIconWidth - width) / 2,
                    (sIconHeight - height) / 2, width, height
                )
                sOldBounds.set(0, 0, bitmapWidth, bitmapHeight)
                sCanvas.drawBitmap(bitmap, sOldBounds, sBounds, sPaint)
                return thumb
            } else if (bitmapWidth < width || bitmapHeight < height) {
                val c = Bitmap.Config.ARGB_8888
                val thumb = Bitmap.createBitmap(
                    sIconWidth,
                    sIconHeight, c
                )
                sCanvas.setBitmap(thumb)
                sPaint.isDither = false
                sPaint.isFilterBitmap = true
                sCanvas.drawBitmap(
                    bitmap, (sIconWidth - bitmapWidth) / 2f,
                    (sIconHeight - bitmapHeight) / 2f, sPaint
                )
                return thumb
            }
        }

        return bitmap
    }

    /**
     * 生成水印图片 水印在右下角
     *
     * @param src       the bitmap object you want proecss
     * @param watermark the water mark above the src
     * @return return a bitmap object ,if paramter's length is 0,return null
     */
    fun createWatermarkBitmap(src: Bitmap?, watermark: Bitmap): Bitmap? {
        if (src == null) {
            return null
        }

        val w = src.width
        val h = src.height
        val ww = watermark.width
        val wh = watermark.height
        // create the new blank bitmap
        val newb = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)// 创建一个新的和SRC长度宽度一样的位图
        val cv = Canvas(newb)
        // draw src into
        cv.drawBitmap(src, 0f, 0f, null)// 在 0，0坐标开始画入src
        // draw watermark into
        cv.drawBitmap(watermark, w - ww + 5f, h - wh + 5f, null)// 在src的右下角画入水印
        // save all clip
        cv.save()// 保存
        // store
        cv.restore()// 存储
        return newb
    }

    /**
     * 重新编码Bitmap
     *
     * @param src     需要重新编码的Bitmap
     * @param format  编码后的格式（目前只支持png和jpeg这两种格式）
     * @param quality 重新生成后的bitmap的质量
     * @return 返回重新生成后的bitmap
     */
    fun codec(
        src: Bitmap, format: Bitmap.CompressFormat,
        quality: Int
    ): Bitmap {
        val os = ByteArrayOutputStream()
        src.compress(format, quality, os)

        val array = os.toByteArray()
        return BitmapFactory.decodeByteArray(array, 0, array.size)
    }

    /**
     * 图片压缩方法：（使用compress的方法）
     *
     *
     * <br></br>
     * **说明** 如果bitmap本身的大小小于maxSize，则不作处理
     *
     * @param bitmap  要压缩的图片
     * @param maxSize 压缩后的大小，单位kb
     */
    fun compress(bitmap: Bitmap, maxSize: Double) {
        var bitmap = bitmap
        // 将bitmap放至数组中，意在获得bitmap的大小（与实际读取的原文件要大）
        val baos = ByteArrayOutputStream()
        // 格式、质量、输出流
        bitmap.compress(Bitmap.CompressFormat.PNG, 70, baos)
        val b = baos.toByteArray()
        // 将字节换成KB
        val mid = (b.size / 1024).toDouble()
        // 获取bitmap大小 是允许最大大小的多少倍
        val i = mid / maxSize
        // 判断bitmap占用空间是否大于允许最大空间 如果大于则压缩 小于则不压缩
        if (i > 1) {
            // 缩放图片 此处用到平方根 将宽带和高度压缩掉对应的平方根倍
            // （保持宽高不变，缩放后也达到了最大占用空间的大小）
            bitmap = scale(
                bitmap, bitmap.width / Math.sqrt(i),
                bitmap.height / Math.sqrt(i)
            )
        }
    }

    /**
     * 图片的缩放方法
     *
     * @param src       ：源图片资源
     * @param newWidth  ：缩放后宽度
     * @param newHeight ：缩放后高度
     */
    fun scale(src: Bitmap, newWidth: Double, newHeight: Double): Bitmap {
        // 记录src的宽高
        val width = src.width.toFloat()
        val height = src.height.toFloat()
        // 创建一个matrix容器
        val matrix = Matrix()
        // 计算缩放比例
        val scaleWidth = newWidth.toFloat() / width
        val scaleHeight = newHeight.toFloat() / height
        // 开始缩放
        matrix.postScale(scaleWidth, scaleHeight)
        // 创建缩放后的图片
        return Bitmap.createBitmap(
            src, 0, 0, width.toInt(), height.toInt(),
            matrix, true
        )
    }

    /**
     * 图片的缩放方法
     *
     * @param src         ：源图片资源
     * @param scaleMatrix ：缩放规则
     */
    fun scale(src: Bitmap, scaleMatrix: Matrix): Bitmap {
        return Bitmap.createBitmap(
            src, 0, 0, src.width, src.height,
            scaleMatrix, true
        )
    }

    /**
     * 图片的缩放方法
     *
     * @param src    ：源图片资源
     * @param scaleX ：横向缩放比例
     * @param scaleY ：纵向缩放比例
     */
    fun scale(src: Bitmap, scaleX: Float, scaleY: Float): Bitmap {
        val matrix = Matrix()
        matrix.postScale(scaleX, scaleY)
        return Bitmap.createBitmap(
            src, 0, 0, src.width, src.height,
            matrix, true
        )
    }

    /**
     * 图片的缩放方法
     *
     * @param src   ：源图片资源
     * @param scale ：缩放比例
     */
    fun scale(src: Bitmap, scale: Float): Bitmap {
        return scale(src, scale, scale)
    }

    /**
     * 旋转图片
     *
     * @param angle  旋转角度
     * @param bitmap 要旋转的图片
     * @return 旋转后的图片
     */
    fun rotate(bitmap: Bitmap, angle: Float): Bitmap {
        val matrix = Matrix()
        matrix.postRotate(angle)
        return Bitmap.createBitmap(
            bitmap, 0, 0, bitmap.width,
            bitmap.height, matrix, true
        )
    }

    /**
     * 水平翻转处理
     *
     * @param bitmap 原图
     * @return 水平翻转后的图片
     */
    fun reverseByHorizontal(bitmap: Bitmap): Bitmap {
        val matrix = Matrix()
        matrix.preScale(-1f, 1f)
        return Bitmap.createBitmap(
            bitmap, 0, 0, bitmap.width,
            bitmap.height, matrix, false
        )
    }

    /**
     * 垂直翻转处理
     *
     * @param bitmap 原图
     * @return 垂直翻转后的图片
     */
    fun reverseByVertical(bitmap: Bitmap): Bitmap {
        val matrix = Matrix()
        matrix.preScale(1f, -1f)
        return Bitmap.createBitmap(
            bitmap, 0, 0, bitmap.width,
            bitmap.height, matrix, false
        )
    }

    /**
     * 更改图片色系，变亮或变暗
     *
     * @param delta 图片的亮暗程度值，越小图片会越亮，取值范围(0,24)
     * @return
     */
    fun adjustTone(src: Bitmap, delta: Int): Bitmap? {
        if (delta >= 24 || delta <= 0) {
            return null
        }
        // 设置高斯矩阵
        val gauss = intArrayOf(1, 2, 1, 2, 4, 2, 1, 2, 1)
        val width = src.width
        val height = src.height
        val bitmap = Bitmap.createBitmap(
            width, height,
            Bitmap.Config.RGB_565
        )

        var pixR = 0
        var pixG = 0
        var pixB = 0
        var pixColor = 0
        var newR = 0
        var newG = 0
        var newB = 0
        var idx = 0
        val pixels = IntArray(width * height)

        src.getPixels(pixels, 0, width, 0, 0, width, height)
        var i = 1
        val length = height - 1
        while (i < length) {
            var k = 1
            val len = width - 1
            while (k < len) {
                idx = 0
                for (m in -1..1) {
                    for (n in -1..1) {
                        pixColor = pixels[(i + m) * width + k + n]
                        pixR = Color.red(pixColor)
                        pixG = Color.green(pixColor)
                        pixB = Color.blue(pixColor)

                        newR += pixR * gauss[idx]
                        newG += pixG * gauss[idx]
                        newB += pixB * gauss[idx]
                        idx++
                    }
                }
                newR /= delta
                newG /= delta
                newB /= delta
                newR = Math.min(255, Math.max(0, newR))
                newG = Math.min(255, Math.max(0, newG))
                newB = Math.min(255, Math.max(0, newB))
                pixels[i * width + k] = Color.argb(255, newR, newG, newB)
                newR = 0
                newG = 0
                newB = 0
                k++
            }
            i++
        }
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
        return bitmap
    }

    /**
     * 将彩色图转换为黑白图
     *
     * @param bmp 位图
     * @return 返回转换好的位图
     */
    fun convertToBlackWhite(bmp: Bitmap): Bitmap {
        val width = bmp.width
        val height = bmp.height
        val pixels = IntArray(width * height)
        bmp.getPixels(pixels, 0, width, 0, 0, width, height)

        val alpha = 0xFF shl 24 // 默认将bitmap当成24色图片
        for (i in 0..height - 1) {
            for (j in 0 until width) {
                var grey = pixels[width * i + j]

                val red = grey and 0x00FF0000 shr 16
                val green = grey and 0x0000FF00 shr 8
                val blue = grey and 0x000000FF

                grey = (red * 0.3 + green * 0.59 + blue * 0.11).toInt()
                grey = alpha or (grey shl 16) or (grey shl 8) or grey
                pixels[width * i + j] = grey
            }
        }
        val newBmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
        newBmp.setPixels(pixels, 0, width, 0, 0, width, height)
        return newBmp
    }

    /**
     * 读取图片属性：图片被旋转的角度
     *
     * @param path 图片绝对路径
     * @return 旋转的角度
     */
    fun getImageDegree(path: String): Int {
        var degree = 0
        try {
            val exifInterface = ExifInterface(path)
            val orientation = exifInterface.getAttributeInt(
                ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL
            )
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> degree = 90
                ExifInterface.ORIENTATION_ROTATE_180 -> degree = 180
                ExifInterface.ORIENTATION_ROTATE_270 -> degree = 270
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return degree
    }

    /**
     * 将YUV格式的图片的源数据从横屏模式转为竖屏模式，注意：将源图片的宽高互换一下就是新图片的宽高
     *
     * @param sourceData YUV格式的图片的源数据
     * @param width      源图片的宽
     * @param height     源图片的高
     * @return
     */
    fun yuvLandscapeToPortrait(
        sourceData: ByteArray,
        width: Int, height: Int
    ): ByteArray {
        val rotatedData = ByteArray(sourceData.size)
        for (y in 0 until height) {
            for (x in 0 until width)
                rotatedData[x * height + height - y - 1] = sourceData[x + y * width]
        }
        return rotatedData
    }


    /**
     * A safer decodeStream method
     * rather than the one of [BitmapFactory]
     * which will be easy to get OutOfMemory Exception
     * while loading a big image file.
     *
     * @param uri 压缩相册返回的照片
     * @return
     * @throws FileNotFoundException
     */
    @Throws(FileNotFoundException::class)
    fun safeDecodeStream(uri: Uri, targetWidth: Int, targetHeight: Int, mContext: Context): Bitmap {
        val options = BitmapFactory.Options()
        val resolver = mContext.contentResolver
        options.inJustDecodeBounds = true
        BitmapFactory.decodeStream(
            BufferedInputStream(resolver.openInputStream(uri), 16 * 1024), null, options
        )
        // 得到图片的宽度、高度；
        val imgWidth = options.outWidth.toFloat()
        val imgHeight = options.outHeight.toFloat()
        // 分别计算图片宽度、高度与目标宽度、高度的比例；取大于等于该比例的最小整数；
        val widthRatio = Math.ceil((imgWidth / targetWidth.toFloat()).toDouble()).toInt()
        val heightRatio = Math.ceil((imgHeight / targetHeight.toFloat()).toDouble()).toInt()
        options.inSampleSize = 1
        if (widthRatio > 1 || widthRatio > 1) {
            if (widthRatio > heightRatio) {
                options.inSampleSize = widthRatio
            } else {
                options.inSampleSize = heightRatio
            }
        }
        // 设置好缩放比例后，加载图片进内容；
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeStream(
            BufferedInputStream(
                resolver.openInputStream(uri),
                16 * 1024
            ), null, options
        )!!
    }

    /**
     * bitmap转化为缩略图
     */
    fun bitmap2Thumbnail(srcBitmap: Bitmap, fileName: String): Boolean {
        val matrix = Matrix()
        matrix.setScale(0.3f, 0.3f)
        val bitmap =
            Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.width, srcBitmap.height, matrix, true)
        val bitmapFile = File(fileName)
        FileUtil.createOrExistsFile(bitmapFile)
        var fos: FileOutputStream? = null
        return try {
            fos = FileOutputStream(bitmapFile)
            bitmap.compress(Bitmap.CompressFormat.WEBP, 80, fos)
            fos.flush()
            true
        } catch (e: Exception) {
            e.printStackTrace()
            bitmapFile.delete()
            false
        } finally {
            bitmap.recycle()
            fos?.close()
            true
        }
    }

    // bitmap转化为分享文件
    fun saveBitmap2file(bitmap: Bitmap, file: String): Boolean {
        var success = false
        val fileImage = File(file)
        if (!fileImage.exists())
            FileUtil.createOrExistsFile(fileImage)
        var fileOutputStream: FileOutputStream? = null
        try {
            fileOutputStream = FileOutputStream(fileImage)
            val format = when {
                file.endsWith("jpeg", true) -> Bitmap.CompressFormat.JPEG
                file.endsWith("png", true) -> Bitmap.CompressFormat.PNG
                file.endsWith("webp", true) -> Bitmap.CompressFormat.WEBP
                else -> Bitmap.CompressFormat.JPEG
            }
            bitmap.compress(format, 100, fileOutputStream)
            fileOutputStream.flush()
            success = true
//            Utils.app.sendBroadcast(
//                Intent(
//                    Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
//                    Uri.parse("file://$file")
//                )
//            )
        } catch (e: Exception) {
            e.printStackTrace()
            fileImage.delete()
            success = false
        } finally {
            if (fileOutputStream != null)
                CloseUtil.closeIO(fileOutputStream!!)
            return success
        }
    }

    fun convertUriToFile(activity: Activity, uri: Uri): File? {
        var file: File? = null
        try {
            val proj = arrayOf(
                MediaStore.Images.Media.DATA
            )
            val actualimagecursor = activity.managedQuery(
                uri, proj, null,
                null, null
            )
            if (actualimagecursor != null) {
                val actual_image_column_index = actualimagecursor
                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
                actualimagecursor.moveToFirst()
                val img_path = actualimagecursor
                    .getString(actual_image_column_index)
                if (!TextUtils.isEmpty(img_path)) {
                    file = File(img_path)
                }
            } else {
                file = File(URI(uri.toString()))
                if (file.exists()) {
                    return file
                }
            }
        } catch (e: Exception) {
        }
        return file
    }

    fun getBitmapNearestSize(file: File?, size: Int): Bitmap? {
        try {
            if (file == null || !file.exists()) {
                return null
            } else if (file.length() == 0L) {
                file.delete()
                return null
            }
            val opts = BitmapFactory.Options()
            opts.inJustDecodeBounds = true
            BitmapFactory.decodeFile(file.absolutePath, opts)
            val sampleSize = getSampleSize(
                opts.outHeight.coerceAtMost(opts.outWidth), size
            )
            opts.inSampleSize = sampleSize
            opts.inJustDecodeBounds = false
            opts.inPurgeable = true
            opts.inInputShareable = false
            opts.inPreferredConfig = Bitmap.Config.ARGB_8888
            return BitmapFactory.decodeFile(file.absolutePath, opts)
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }

    fun getSampleSize(fileSize: Int, targetSize: Int): Int {
        var sampleSize = 1
        if (fileSize > targetSize * 2) {
            var sampleLessThanSize = 0
            do {
                sampleLessThanSize++
            } while (fileSize / sampleLessThanSize > targetSize)
            for (i in 1..sampleLessThanSize) {
                if (abs(fileSize / i - targetSize) <= abs(
                        fileSize
                                / sampleSize - targetSize
                    )
                ) {
                    sampleSize = i
                }
            }
        } else {
            sampleSize = if (fileSize <= targetSize) {
                1
            } else {
                2
            }
        }
        return sampleSize
    }


    fun getBitmapFromByteArray(bytes: ByteArray, viewWidth: Int, viewHeight: Int): Bitmap {
        val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
        var w = 0
        var h = 0
        if (bitmap.width < bitmap.height) {
            w = viewWidth
            h = viewWidth * bitmap.height / bitmap.width
        } else {
            h = viewHeight
            w = bitmap.width * viewHeight / bitmap.height
        }
        val width = bitmap.width
        val height = bitmap.height
        val matrix = Matrix()
        val scaleWidth = w.toFloat() / width
        val scaleHeight = h.toFloat() / height
        matrix.postScale(scaleWidth, scaleHeight)
        return Bitmap.createBitmap(
            bitmap, 0, 0, width, height,
            matrix, true
        )
    }

    //获取图片宽高
    fun getImageWH(path: String, listener: (Int, Int) -> Unit) {
        val opts = BitmapFactory.Options()
        //只请求图片宽高，不解析图片像素(请求图片属性但不申请内存，解析bitmap对象，该对象不占内存)
        opts.inJustDecodeBounds = true
        BitmapFactory.decodeFile(path, opts)
        listener(opts.outWidth, opts.outHeight)
    }
}